package com.zhiqian.community.util;

import org.apache.commons.lang3.CharUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

/**
 * 敏感词过滤器
 */
@Component
public class SensitiveFilter {

    private static final Logger logger= LoggerFactory.getLogger(SensitiveFilter.class);
    private static final TrieNode root = new TrieNode();
    //敏感词替换符
    private static final String REPLACEMENT="***";

    /**
     * 前缀树初始化,在调用这个类的构造器之后
     */
    @PostConstruct
    public void init(){
        try(InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("sensitive-words");
            BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));){
            String sensitive;
            while((sensitive=bufferedReader.readLine())!=null){
                this.addSensitive(sensitive);
            }
        } catch (IOException e) {
            logger.error("加载敏感词文件失败："+e.getMessage());
        }

    }

    /**
     * 向前缀树中添加敏感词
     * @param str
     */
    private void addSensitive(String str) {
        if (StringUtils.isBlank(str)) {
            return;
        }
        char[] chars = str.toCharArray();
        int index = 0;
        TrieNode trieNode = root;
        while (index < chars.length) {
            char c = chars[index++];
            if (trieNode.getSubNode(c) == null) {
                TrieNode subNode = new TrieNode();
                trieNode.addSubNode(c, subNode);
            }
            trieNode = trieNode.getSubNode(c);
            if (index==chars.length){
                trieNode.setFlag(true);
            }
        }
    }

    /**
     * 使用前缀树过滤字符串
     * @param text
     * @return
     */
    public String filter(String text) {
        if (StringUtils.isBlank(text)){
            return null;
        }
        int fast=0,slow=0;
        TrieNode trieNode=root;
        StringBuilder stringBuilder = new StringBuilder();
        while(slow<text.length()){
            char c=text.charAt(slow);
            if (isSymbol(c)){
                if (trieNode==root){
                    stringBuilder.append(c);
                    fast++;
                }
                slow++;
                continue;
            }
            trieNode = trieNode.getSubNode(c);
            if (trieNode==null){
                stringBuilder.append(text.charAt(fast));
                slow=++fast;
                trieNode=root;
            }else if (trieNode.isFlag()){
                stringBuilder.append(REPLACEMENT);
                fast=++slow;
                trieNode=root;
            }else{
                slow++;
            }
        }
        stringBuilder.append(text.substring(fast));
        return stringBuilder.toString();
    }

    /**
     * 判断是否为符号
     * @param c
     * @return
     */
    private boolean isSymbol(Character c){
        //0x2E80~0x9FFF 为东亚文字范围，不判定为字符
        return !CharUtils.isAsciiAlphanumeric(c) && (c<0x2E80 || c>0x9FFF);
    }

    //前缀树
    private static class TrieNode {

        private Map<Character, TrieNode> children = new HashMap<>();
        //敏感词结束标识
        private boolean flag=false;

        public boolean isFlag() {
            return flag;
        }

        public void setFlag(boolean flag) {
            this.flag = flag;
        }

        public void addSubNode(Character character, TrieNode node) {
            children.put(character, node);
        }

        //获取子节点
        public TrieNode getSubNode(Character character) {
            return children.get(character);
        }
    }
}
